package com.heima.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.dtos.UserSearchDto;
import com.heima.model.search.vos.SearchArticleVo;
import com.heima.search.service.ApUserSearchService;
import com.heima.search.service.ArticleSearchService;
import com.heima.utils.thread.ApUserThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class ArticleSearchServiceImpl implements ArticleSearchService {

    @Autowired
    private RestHighLevelClient client;

    @Autowired
    private ApUserSearchService apUserSearchService;
    /**
     * 文章搜索功能业务
     * @param dto
     * @return
     */
    @Override
    public ResponseResult search(UserSearchDto dto) throws IOException {

        //todo 1.校验参数
        if(dto == null || StringUtils.isBlank(dto.getSearchWords())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }

        //todo 2.es 查询  （麻烦）
        //todo searchSourceBuilder 搜索的条件对象封装（基本条件，关键字查询，分页，高亮）
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();

        //todo 2.1 封装第一个关键字搜索条件   (BUG:搜索条件没有生效，但是其他业务成功)
        //todo queryBuilder 搜索条件  matchQuery(先分词，再查询)  trimQuery(词条精准查询)
        // QueryStringQuery = matchQuery QueryStringQuery 是 Lucene提供的    matchQuery （ES）
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); //多条件Query

        QueryStringQueryBuilder queryBuilder = QueryBuilders.queryStringQuery(dto.getSearchWords());
        queryBuilder.field("title").field("content"); //and 还是 or
        queryBuilder.defaultOperator(Operator.OR);
        boolQueryBuilder.must(queryBuilder);
        //todo 2.2. 分页查询  from 不是页码，是起始的条数位置的下标   和mysql的Limit 起始位置，查询条数
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(dto.getPageSize());

        //todo 2.3 根据最小时间查询 （查询更多文章） 手机向上滑
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("publishTime");
        rangeQueryBuilder.lt(dto.getMinBehotTime().getTime());
        boolQueryBuilder.filter(rangeQueryBuilder);
        //todo 注意点,.多条件查询必须使用boolQueryBuilder 不能直接添加条件
        searchSourceBuilder.query(boolQueryBuilder);

        //todo 2.4高亮查询
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");//给标题列添加高亮
        highlightBuilder.preTags("<b style='color:red'>");
        highlightBuilder.postTags("</b>");
        searchSourceBuilder.highlighter(highlightBuilder);

        //todo 2.5 排序字段 （根据文章的发布时间，进行从大到小的排序）
        searchSourceBuilder.sort("publishTime", SortOrder.DESC);

        //todo searchRequest es 请求的参数对象 （dto）  参数：代表搜索哪个索引库
        SearchRequest searchRequest = new SearchRequest("app_info_article");
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        //todo 3.封装返回结果
        List<SearchArticleVo> searchArticleVoList = new ArrayList<>();
        SearchHits hits = searchResponse.getHits();
        for (SearchHit searchHit : hits.getHits()) {
            String jsonArticleVo = searchHit.getSourceAsString();
            SearchArticleVo searchArticleVo = JSON.parseObject(jsonArticleVo, SearchArticleVo.class);
            //todo 还欠一个高亮没解决
            //todo 判断是否存在高亮字段，如果存在，设置高亮数据
            if(searchHit.getHighlightFields() != null && searchHit.getHighlightFields().size() > 0){ //代表高亮字段里面有值
                Text[] titles = searchHit.getHighlightFields().get("title").getFragments();
                //titles 代表的就是高亮的字段
                searchArticleVo.setH_title(titles[0].string());
            }else{
                //todo 如果不存在，设置普通数据即可
                searchArticleVo.setH_title(searchArticleVo.getTitle());
            }
            searchArticleVoList.add(searchArticleVo);
        }

        //todo 新业务需求：添加用户的搜索记录
        apUserSearchService.insert(dto.getSearchWords(), ApUserThreadLocalUtil.getUser().getId());
        return ResponseResult.okResult(searchArticleVoList);
    }
}
